import { useDebounceFn } from '@vueuse/core';

import { ref } from 'vue';
import { useIntervalFn } from './useIntervalFn';

/**
 * 通用的设备数值状态同步 Hook
 * 封装了设备值的读取、设置、同步与上报逻辑
 */
export interface UseDeviceValueSyncOptions {
  /**
   * 获取设备当前数值的方法
   * 应返回 0~100 之间的值，支持同步或异步
   */
  get: () => Promise<number> | number

  /**
   * 设置设备目标数值的方法
   * 应设置 0~100 之间的值，支持同步或异步
   */
  set: (val: number) => Promise<void> | void

  /**
   * 同步间隔（单位：ms），默认 1000 毫秒
   */
  syncInterval?: number

  /**
   * 值变化时回调（如需上报给服务端）
   */
  onReport?: (val: number) => void

  /**
   * 容许误差（单位：数值差），默认 1，避免精度波动触发变更
   */
  epsilon?: number
}

/**
 * useDeviceValueSync 返回结果类型
 */
export interface UseDeviceValueSyncReturn {
  /**
   * 当前设备读取到的实际数值
   */
  current: ReturnType<typeof ref<number>>

  /**
   * 当前希望设置的目标数值
   */
  target: ReturnType<typeof ref<number>>

  /**
   * 设置目标值的方法（会停止同步、执行设置后再恢复同步）
   */
  set: (val: number) => Promise<void>

  /**
   * 启动定时同步（从设备读取当前值）
   */
  startSync: () => void

  /**
   * 停止定时同步
   */
  stopSync: () => void

  /**
   * 主动上报当前值（例如推送给服务端）
   */
  report: () => void
}

/**
 * 通用设备数值同步 Hook
 * @param options UseDeviceValueSyncOptions
 * @returns UseDeviceValueSyncReturn
 */
export function useDeviceValueSync(
  options: UseDeviceValueSyncOptions
): UseDeviceValueSyncReturn {
  const current = ref(0);
  const target = ref(0);
  const isSetting = ref(false);

  const epsilon = options.epsilon ?? 1;

  const { resume: startSync, pause: stopSync } = useIntervalFn(
    async () => {
      if (isSetting.value)
        return;

      try {
        const val = await options.get();
        if (Math.abs(val - target.value) > epsilon) {
          current.value = val;
        }
      }
      catch (err) {
        console.warn('设备同步失败:', err);
      }
    },
    options.syncInterval || 1000,
    { immediate: false }
  );

  // 上报
  const report = () => {
    options.onReport?.(current.value);
  };

  // 防抖上报
  const debounceReport = useDebounceFn(() => {
    report();
  }, 300);

  const set = async (val: number) => {
    stopSync();
    isSetting.value = true;
    target.value = val;

    try {
      if (val === current.value)
        return;
      await options.set(val);
      current.value = val;
      // 上报
      debounceReport();
    }
    catch (err) {
      console.warn('设置设备值失败:', err);
    }
    finally {
      isSetting.value = false;
      startSync();
    }
  };

  return {
    current,
    target,
    set,
    startSync,
    stopSync,
    report
  };
}
